﻿using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.IO;
using System.Xml;
using System.Security.Cryptography;
using System.Xml.Linq;
using FileInfo = AutoUpdateB.Info.FileInfo;
using System.Linq;

namespace AutoUpdateB
{
    internal class UpdateHelper
    {
        //解压文件，并将其解压到目标路径
        public static void ExtraFile(string zipPath, string extractPath)
        {
            using (ZipArchive archive = ZipFile.OpenRead(zipPath))
            {
                foreach (ZipArchiveEntry entry in archive.Entries)
                {
                    string fullPath = Path.Combine(extractPath, entry.FullName);

                    // 如果是目录，则创建它
                    if (entry.FullName.EndsWith("/") || entry.FullName.EndsWith("\\"))
                    {
                        Directory.CreateDirectory(fullPath);
                        continue;
                    }

                    string directory = Path.GetDirectoryName(fullPath);
                    if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
                    {
                        Directory.CreateDirectory(directory);
                    }

                    // 如果文件已存在则删除它
                    if (File.Exists(fullPath))
                    {
                        File.Delete(fullPath);
                    }

                    entry.ExtractToFile(fullPath);
                }
            }
        }



        /// <summary>
        /// 将文件从temp文件夹转移至安装目录
        /// </summary>
        /// <param name="source">源目录</param>
        /// <param name="target">安装目录</param>
        /// 
        public static void MoveFiles(string source, string target)
        {
            try
            {
                if (!Directory.Exists(target)) return;

                var files = Directory.GetFiles(target, "*.*", SearchOption.AllDirectories);
                foreach (var file in files)
                {
                    // 获取相对于 tempFolderPath 的文件路径
                    string relativeFilePath = file.Substring(target.Length + 1);

                    // 构建目标文件的完整路径
                    string destFile = Path.Combine(source, relativeFilePath);

                    // 确保目标目录存在
                    string destDirectory = Path.GetDirectoryName(destFile);
                    if (!string.IsNullOrEmpty(destDirectory) && !Directory.Exists(destDirectory))
                    {
                        Directory.CreateDirectory(destDirectory);
                    }

                    // 拷贝文件
                    System.IO.File.Copy(file, destFile, true);
                }

                // 删除临时文件夹及其内容
                Directory.Delete(source, true);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"更新下载失败{ex.Message}");
            }
        }


        /// <summary>
        /// 当更新完成之后用于更新本地xml的版本信息
        /// </summary>
        /// <param name="latestVersion">待更新的信息</param>
        /// <param name="targetXmlPath">待更新的文件路径</param>
        public static void UpdateLocalXml(string latestVersion, string targetXmlPath)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(targetXmlPath);
            XmlNode versionNode = doc.SelectSingleNode("/Configuration/CurrentVersion");

            if (versionNode != null)
            {
                versionNode.InnerText = latestVersion;
                doc.Save(targetXmlPath);
                Console.WriteLine($"本地版本号更新成功！版本号为{latestVersion}");
            }
        }


        /// <summary>
        /// 校验单个文件
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <param name="expectedMd5">参考md5值</param>
        /// <returns></returns>
        public static bool VerifyFile(string filePath, string expectedMd5)
        {
            using (MD5 md5 = MD5.Create())
            {
                using (FileStream stream = System.IO.File.OpenRead(filePath))
                {
                    byte[] hash = md5.ComputeHash(stream);
                    string fileMd5 = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
                    return fileMd5.Equals(expectedMd5, StringComparison.OrdinalIgnoreCase);
                }
            }
        }

        public static List<FileInfo> ParseFullZip(XElement versionElement)
        {
            var fileList = new List<FileInfo>();

            if (versionElement != null)
            {
                foreach (var fileElement in versionElement.Elements("full_zip"))
                {
                    fileList.Add(new FileInfo
                    {
                        FilePath = fileElement.Element("filepath")?.Value,
                        FileSize = long.Parse(fileElement.Element("filesize")?.Value),
                        Md5 = fileElement.Element("filemd5")?.Value
                    });
                }
            }

            return fileList;
        }

        /// <summary>
        /// 解析文件列表
        /// </summary>
        /// <param name="versionElement"></param>
        /// <returns></returns>
        public static List<FileInfo> ParseFileList(XElement versionElement)
        {

            var fileList = new List<FileInfo>();

            if (versionElement != null)
            {
                foreach (var fileElement in versionElement.Element("file_list")?.Elements("file"))
                {
                    fileList.Add(new FileInfo
                    {
                        FilePath = fileElement.Element("filepath")?.Value,
                        FileSize = long.Parse(fileElement.Element("filesize")?.Value),
                        Md5 = fileElement.Element("filemd5")?.Value
                    });
                }
            }
            return fileList;

        }


        //用于获取指定xml的某个字段
        public static string GetXmlElem(XDocument xdoc, string field)
        {
            return xdoc.Descendants($"{field}").FirstOrDefault()?.Value;
        }


        /// <summary>
        /// 获得需要更新的文件列表。
        /// </summary>
        /// <returns></returns>
        public static List<FileInfo> GetNeedUpdateFilelist(XDocument remoteDoc,string installPath)
        {
            List<FileInfo> filelist2 = new List<FileInfo>();
            try
            {
                var latestVersionElement = remoteDoc.Descendants("version").FirstOrDefault();
                List<FileInfo> filelist1 = UpdateHelper.ParseFileList(latestVersionElement);
                foreach (var remotefile in filelist1)
                {
                    var localFile = new System.IO.FileInfo(Path.Combine(installPath, remotefile.FilePath));
                    if (!System.IO.File.Exists(localFile.FullName)            // 1.判断文件是否存在
                        || remotefile.FileSize != localFile.Length            // 2.判断文件大小是否相同
                        || !VerifyFile(localFile.FullName, remotefile.Md5))   // 3.判断MD5是否相同
                    {
                        remotefile.LocalAbsolutePath = localFile.FullName;
                        filelist2.Add(remotefile);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message); //应该进行日志记录。
            }
            return filelist2;
        }

    }
}
